home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / src / out-of-phase-102-c / OutOfPhase 1.02 Source / OutOfPhase Folder / Level 0 Macintosh 29Sep94 / Screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-23  |  47.6 KB  |  1,578 lines  |  [TEXT/KAHL]

  1. /* Screen.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    System Dependency Library for Building Portable Software               */
  5. /*    Macintosh Version                                                      */
  6. /*    Written by Thomas R. Lawrence, 1993 - 1994.                            */
  7. /*                                                                           */
  8. /*    This file is Public Domain; it may be used for any purpose whatsoever  */
  9. /*    without restriction.                                                   */
  10. /*                                                                           */
  11. /*    This package is distributed in the hope that it will be useful,        */
  12. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  13. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                   */
  14. /*                                                                           */
  15. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  16. /*                                                                           */
  17. /*****************************************************************************/
  18.  
  19. #include "MiscInfo.h"
  20. #include "Debug.h"
  21. #include "Audit.h"
  22. #include "Definitions.h"
  23.  
  24. #ifdef THINK_C
  25.     #pragma options(pack_enums)
  26. #endif
  27. #include <Quickdraw.h>
  28. #include <Windows.h>
  29. #include <Menus.h>
  30. #include <Fonts.h>
  31. #include <TextEdit.h>
  32. #include <Dialogs.h>
  33. #include <Script.h>
  34. #include <GestaltEqu.h>
  35. #ifdef THINK_C
  36.     #pragma options(!pack_enums)
  37. #endif
  38.  
  39. #include "Screen.h"
  40. #include "Menus.h"
  41. #include "Memory.h"
  42. #include "EventLoop.h"
  43. #include "Scrap.h"
  44. #include "Array.h"
  45. #include "Files.h"
  46.  
  47.  
  48. /* maximum string length that can be sized in a single call to TextWidth or DrawText */
  49. /* (such a big number doesn't actually make much sense since 65535 is the number of */
  50. /* pixels, so if there are 32767 chars, we are way over the QuickDraw limit.) */
  51. #define MAXTEXTSIZING (32767)
  52.  
  53.  
  54. /* this structure contains everything about a window */
  55. struct WinType
  56.     {
  57.         /* document window or dialog box */
  58.         WinForm                                WhatKindOfWindow;
  59.         /* callback routine for redrawing it */
  60.         void                                    (*UpdateRoutine)(void* Refcon);
  61.         /* reference value for callback */
  62.         void*                                    Refcon;
  63.         /* current clip rect (for AddClipRect) */
  64.         Rect                                    CurrentClipRect;
  65.         /* actual window record */
  66.         WindowRecord                    ActualWindow;
  67.     };
  68.  
  69.  
  70. /* structure for bitmap */
  71. struct Bitmap
  72.     {
  73.         /* bytes per row for larger than image or partial bitmaps */
  74.         short                                    BytesPerRow; /* 2 bytes */
  75.         /* dimensions of bitmap */
  76.         OrdType                                Width; /* 2 bytes */
  77.         OrdType                                Height; /* 2 bytes */
  78.         /* the bitmap that the system uses */
  79.         BitMap                                SystemBitmap; /* 14 bytes */
  80.         /* data array here (block will actually be as large as necessary) */
  81.         unsigned char                    Data[1]; /* long word aligned (20th offset) */
  82.     };
  83.  
  84.  
  85. /* list of windows */
  86. static ArrayRec*                    OurWindowList;
  87.  
  88. /* list of windows that need to be updated */
  89. static ArrayRec*                    PendingDeferredUpdates;
  90.  
  91. /* debugging flag */
  92. EXECUTE(static MyBoolean    Initialized = False;)
  93.  
  94. /* pattern bitmap definitions.  patterns are 8x8 pixel blocks */
  95. static unsigned char            PatternMapping[5][8] =
  96.     {
  97.         {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /* White */
  98.         {0x88,0x22,0x88,0x22,0x88,0x22,0x88,0x22}, /* Light Grey */
  99.         {0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55}, /* Medium Grey */
  100.         {0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD}, /* Dark Grey */
  101.         {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} /* Black */
  102.     };
  103.  
  104. /* since I don't know how to get a list of fonts, I make this menu */
  105. /* which contains all of the fonts and then I extract the names from it */
  106. static MenuHandle                    FunnyFontMenu;
  107.  
  108. /* this array contains all of the modal dialog boxes.  the most recent one is */
  109. /* at the end of the array */
  110. static ArrayRec*                    DialogBoxList; /* of WinType's */
  111.  
  112.  
  113. /* Initialize the screen management subsystem.  This routine must be called before */
  114. /* any graphics routines are called.  this routine initializes the entire Level 0 */
  115. /* module set except for some optional modules (like Network).  if it returns  */
  116. /* False then initialization failed and the program must terminate immediately. */
  117. MyBoolean                        InitializeScreen(void)
  118.     {
  119.         ERROR(Initialized,PRERR(ForceAbort,"InitializeScreen called more than once"));
  120.         /* initialize operating system managers */
  121.         InitGraf(&qd.thePort);
  122.         InitFonts();
  123.         InitWindows();
  124.         TEInit();
  125.         InitDialogs(NIL);
  126.         InitCursor();
  127.         InitMenus();
  128. #ifdef THINK_C
  129.     #if /*__option(mc68020) ||*/ __option(mc68881)
  130.         {
  131.             long                Result;
  132.  
  133.             if (noErr != Gestalt(gestaltFPUType,&Result))
  134.                 {
  135.                     return False;
  136.                 }
  137.             if (Result == gestaltNoFPU)
  138.                 {
  139.                     PRERR(ForceAbort,"This program requires a floating point coprocessor.");
  140.                     return False;
  141.                 }
  142.         }
  143.     #endif
  144.     #if __option(profile)
  145.         {
  146.             void                InitializeProfile(void);
  147.  
  148.             InitializeProfile();
  149.         }
  150.     #endif
  151. #endif
  152.         /* initialize our local memory manager */
  153.         if (!Eep_InitMemory())
  154.             {
  155.              FailurePoint1:
  156.                 return False;
  157.             }
  158.         /* initialize error handling.  no return code from this */
  159.         Eep_InitPRERR();
  160.         /* initialize our window array */
  161.         OurWindowList = NewArray();
  162.         if (OurWindowList == NIL)
  163.             {
  164.              FailurePoint2:
  165.                 Eep_FlushMemory();
  166.                 goto FailurePoint1;
  167.             }
  168.         /* initialize our deferred update list */
  169.         PendingDeferredUpdates = NewArray();
  170.         if (PendingDeferredUpdates == NIL)
  171.             {
  172.              FailurePoint3:
  173.                 DisposeArray(OurWindowList);
  174.                 goto FailurePoint2;
  175.             }
  176.         /* create dialog box array here */
  177.         DialogBoxList = NewArray();
  178.         if (DialogBoxList == NIL)
  179.             {
  180.              FailurePoint4:
  181.                 DisposeArray(PendingDeferredUpdates);
  182.                 goto FailurePoint3;
  183.             }
  184.         /* initialize cut and paste */
  185.         if (!Eep_InitializeScrapHandler())
  186.             {
  187.              FailurePoint5:
  188.                 DisposeArray(DialogBoxList);
  189.                 goto FailurePoint4;
  190.             }
  191.         /* initialize event loop */
  192.         if (!Eep_InitEventLoop())
  193.             {
  194.              FailurePoint6:
  195.                 Eep_ShutdownScrapHandler();
  196.                 goto FailurePoint5;
  197.             }
  198.         /* initialize menu subsystem */
  199.         if (!Eep_InitializeMenus())
  200.             {
  201.              FailurePoint7:
  202.                 Eep_ShutdownEventLoop();
  203.                 goto FailurePoint6;
  204.             }
  205.         /* initialize file system */
  206.         if (!Eep_InitializeFiles())
  207.             {
  208.              FailurePoint8:
  209.                 Eep_ShutdownMenus();
  210.                 goto FailurePoint7;
  211.             }
  212.         /* create the font menu for obtaining names of fonts */
  213.         /* menu manager uses menu IDs 256 and up, so we'll grab ID 1 */
  214.         FunnyFontMenu = NewMenu(1,"\pSilly Stupid Little Font Menu");
  215.         if (FunnyFontMenu == NIL)
  216.             {
  217.              FailurePoint9:
  218.                 Eep_ShutdownFiles();
  219.                 goto FailurePoint8;
  220.             }
  221.         AddResMenu(FunnyFontMenu,'FONT');
  222.         /* initialization done */
  223.         EXECUTE(Initialized = True;)
  224.         return True;
  225.     }
  226.  
  227.  
  228. /* close all open windows and perform any cleanup or server disconnection before */
  229. /* the program terminates */
  230. void                                ShutdownScreen(void)
  231.     {
  232.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  233.         /* shutdown subsystems in reverse order */
  234.         DisposeMenu(FunnyFontMenu); /* get rid of the funny font menu */
  235.         Eep_ShutdownFiles();
  236.         Eep_ShutdownMenus();
  237.         Eep_ShutdownEventLoop();
  238.         Eep_ShutdownScrapHandler();
  239.         /* clean up our own data structures */
  240.         ERROR(ArrayGetLength(OurWindowList) != 0,PRERR(AllowResume,
  241.             "ShutdownScreen:  there are still some windows open"));
  242.         DisposeArray(OurWindowList);
  243.         DisposeArray(PendingDeferredUpdates);
  244.         DisposeArray(DialogBoxList);
  245.         /* dump memory subsystem */
  246.         Eep_FlushMemory();
  247.         Eep_ShutdownPRERR();
  248.         EXECUTE(Initialized = False;)
  249. #ifdef THINK_C
  250.     #if __option(profile)
  251.         {
  252.             void                DumpProfile(void);
  253.             void                ProfileKillElement(unsigned char* FunctionName);
  254.  
  255.             ProfileKillElement("\pGetAnEvent");
  256.             ProfileKillElement("\pRelinquishCPUCheckCancel");
  257.             ProfileKillElement("\pPutFile");
  258.             ProfileKillElement("\pGetFileStandard");
  259.             ProfileKillElement("\pGetFileAny");
  260.             DumpProfile();
  261.         }
  262.     #endif
  263. #endif
  264.     }
  265.  
  266.  
  267. /* get size of screen.  If there are multiple screens, the result is implementation */
  268. /* defined, but should not be counted on.  On the Macintosh, this returns only the */
  269. /* size of the main screen.  Caveats aside, you are guarranteed that there is at */
  270. /* least this much screen space in the form of a complete rectangle. */
  271. OrdType                            GetScreenHeight(void)
  272.     {
  273.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  274.         return qd.screenBits.bounds.bottom - qd.screenBits.bounds.top - GetMBarHeight();
  275.     }
  276.  
  277.  
  278. /* get size of screen.  If there are multiple screens, the result is implementation */
  279. /* defined, but should not be counted on.  On the Macintosh, this returns only the */
  280. /* size of the main screen.  Caveats aside, you are guarranteed that there is at */
  281. /* least this much screen space in the form of a complete rectangle. */
  282. OrdType                            GetScreenWidth(void)
  283.     {
  284.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  285.         return qd.screenBits.bounds.right - qd.screenBits.bounds.left;
  286.     }
  287.  
  288.  
  289. /* how big is a window's title bar */
  290. OrdType                            WindowTitleBarHeight(WinForm WindowKind)
  291.     {
  292.         switch (WindowKind)
  293.             {
  294.                 case eDocumentWindow:
  295.                     return 19;
  296.                 case eDialogWindow:
  297.                 case eModelessDialogWindow:
  298.                     return 6;
  299.                 default:
  300.                     EXECUTE(PRERR(AllowResume,"WindowTitleBarHeight:  Unknown window type"));
  301.             }
  302.     }
  303.  
  304.  
  305. /* how big are the other edges of a window */
  306. OrdType                            WindowOtherEdgeWidths(WinForm WindowKind)
  307.     {
  308.         switch (WindowKind)
  309.             {
  310.                 case eDocumentWindow:
  311.                     return 2;
  312.                 case eDialogWindow:
  313.                 case eModelessDialogWindow:
  314.                     return 6;
  315.                 default:
  316.                     EXECUTE(PRERR(AllowResume,"WindowTitleBarHeight:  Unknown window type"));
  317.             }
  318.     }
  319.  
  320.  
  321. /* create a new window.  if WindowKind = eDocumentWindow, then the window is a */
  322. /* standard window with a name (image is implementation defined).  In this case */
  323. /* Zoomable determines whether there will be a "Maximize" button, and Closable */
  324. /* determines whether there will be a "Close" button. */
  325. /* The window returned will be considered in the "disabled" state and any */
  326. /* objects installed in it should be disabled.  Eventually GetAnEvent will return */
  327. /* an active window change event disabling the window previously on top and */
  328. /* enabling this window.  if there are dialog boxes, then the window will be */
  329. /* created under the lowest dialog box */
  330. WinType*                        MakeNewWindow(WinForm WindowKind, WinCloseType Closable,
  331.                                             WinZoomType Zoomable, WinSizingType Resizing, OrdType Left,
  332.                                             OrdType Top, OrdType Width, OrdType Height,
  333.                                             void (*UpdateRoutine)(void* Refcon), void* Refcon)
  334.     {
  335.         WinType*                    Window;
  336.         Rect                            Where;
  337.         short                            WDef;
  338.  
  339.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  340.         ERROR(UpdateRoutine == NIL,PRERR(ForceAbort,
  341.             "MakeNewWindow:  can't have NIL update routine"));
  342.         /* allocate the window record */
  343.         Window = (WinType*)AllocPtrCanFail(sizeof(WinType),"WindowRecord");
  344.         if (Window == NIL)
  345.             {
  346.              FailurePoint1:
  347.                 return NIL;
  348.             }
  349.         /* add window to window list */
  350.         if (!ArrayAppendElement(OurWindowList,Window))
  351.             {
  352.              FailurePoint2:
  353.                 ReleasePtr((char*)Window);
  354.                 goto FailurePoint1;
  355.             }
  356.         /* create the actual window */
  357.         Where.left = Left;
  358.         Where.top = Top + GetMBarHeight();
  359.         Where.right = Left + Width;
  360.         Where.bottom = Top + Height + GetMBarHeight();
  361.         switch (WindowKind)
  362.             {
  363.                 case eDocumentWindow:
  364.                     if (Zoomable == eWindowZoomable)
  365.                         {
  366.                             WDef = zoomNoGrow;
  367.                         }
  368.                      else
  369.                         {
  370.                             WDef = noGrowDocProc;
  371.                         }
  372.                     break;
  373.                 case eDialogWindow:
  374.                     WDef = dBoxProc;
  375.                     break;
  376.                 case eModelessDialogWindow:
  377.                     WDef = movableDBoxProc;
  378.                     break;
  379.                 default:
  380.                     EXECUTE(PRERR(ForceAbort,"MakeNewWindow:  unknown WindowKind"));
  381.                     break;
  382.             }
  383.         if (NIL == NewWindow(&(Window->ActualWindow),&Where,"\p"/*notitle*/,
  384.             True/*visible*/,WDef,
  385.             (
  386.                 /* is the window a document window when there are dialog windows? */
  387.                 ((ArrayGetLength(DialogBoxList) != 0)
  388.                 && (WindowKind != eDialogWindow)
  389.                 && (WindowKind != eModelessDialogWindow))
  390.             ?
  391.                 /* yes -- create under lowest dialog */
  392.                 (GrafPort*)&(((WinType*)ArrayGetElement(DialogBoxList,0))->ActualWindow)
  393.             :
  394.                 /* no -- create on top */
  395.                 (GrafPort*)-1L/*windowinfront*/
  396.             ),(Closable == eWindowClosable),(long)Window/*refcon is window's base pointer*/))
  397.             {
  398.              FailurePoint3:
  399.                 ArrayDeleteElement(OurWindowList,ArrayFindElement(OurWindowList,Window));
  400.                 goto FailurePoint2;
  401.             }
  402.         /* initialize static fields */
  403.         Window->CurrentClipRect.left = 0;
  404.         Window->CurrentClipRect.top = 0;
  405.         Window->CurrentClipRect.right = Width;
  406.         Window->CurrentClipRect.bottom = Height;
  407.         Window->UpdateRoutine = UpdateRoutine;
  408.         Window->Refcon = Refcon;
  409.         Window->WhatKindOfWindow = WindowKind;
  410.         /* if it's a dialog box, then add it to the list */
  411.         if ((WindowKind == eDialogWindow) || (WindowKind == eModelessDialogWindow))
  412.             {
  413.                 if (!ArrayAppendElement(DialogBoxList,Window))
  414.                     {
  415.                         DisposeWindow((WindowPtr)&(Window->ActualWindow));
  416.                         goto FailurePoint3;
  417.                     }
  418.             }
  419.         return Window;
  420.     }
  421.  
  422.  
  423. /* change the size of the window.  The window will be guarranteed to be the specified */
  424. /* size, but significant portions may not be on screen, so be careful */
  425. void                                ResizeWindow(WinType* Window, OrdType Width, OrdType Height)
  426.     {
  427.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  428.         CheckPtrExistence(Window);
  429.         /* change window size */
  430.         SizeWindow((WindowPtr)&(Window->ActualWindow),Width,Height,False);
  431.         /* invalidate the window so it gets updated */
  432.         SetPort((WindowPtr)&(Window->ActualWindow));
  433.         InvalRect(&(Window->ActualWindow.port.portRect));
  434.     }
  435.  
  436.  
  437. /* close a window and release all associated space.  The window refnum may be reused */
  438. /* An active window change event will be issued activating the window that is */
  439. /* next in the stack.  If there are dialog boxes open, then the most recently */
  440. /* created one must be disposed or it is an error. */
  441. void                                KillWindow(WinType* Window)
  442.     {
  443.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  444.         CheckPtrExistence(Window);
  445.         ERROR((ArrayGetLength(DialogBoxList) != 0) && (ArrayFindElement(DialogBoxList,
  446.             Window) != ArrayGetLength(DialogBoxList) - 1),PRERR(ForceAbort,
  447.             "KillWindow:  dialog boxes exist and window isn't the topmost dialog box."));
  448.         Eep_WindowDying(Window);
  449.         ArrayDeleteElement(OurWindowList,ArrayFindElement(OurWindowList,Window));
  450.         if (ArrayGetLength(DialogBoxList) != 0)
  451.             {
  452.                 ERROR(ArrayFindElement(DialogBoxList,Window) == -1,PRERR(ForceAbort,
  453.                     "KillWindow:  couldn't find dialog box in the list"));
  454.                 ArrayDeleteElement(DialogBoxList,ArrayFindElement(DialogBoxList,Window));
  455.             }
  456.         /* remove it from the pending updates list if it's still there */
  457.         if (ArrayFindElement(PendingDeferredUpdates,Window) >= 0)
  458.             {
  459.                 ArrayDeleteElement(PendingDeferredUpdates,
  460.                     ArrayFindElement(PendingDeferredUpdates,Window));
  461.             }
  462.         /* dispose the OS window */
  463.         DisposeWindow((WindowPtr)&(Window->ActualWindow));
  464.         /* dispose the window object */
  465.         ReleasePtr((char*)Window);
  466.     }
  467.  
  468.  
  469. /* get the size of the usable portion of the window */
  470. OrdType                            GetWindowHeight(WinType* Window)
  471.     {
  472.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  473.         CheckPtrExistence(Window);
  474.         return Window->ActualWindow.port.portRect.bottom
  475.             - Window->ActualWindow.port.portRect.top;
  476.     }
  477.  
  478.  
  479. /* get the size of the usable portion of the window */
  480. OrdType                            GetWindowWidth(WinType* Window)
  481.     {
  482.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  483.         CheckPtrExistence(Window);
  484.         return Window->ActualWindow.port.portRect.right
  485.             - Window->ActualWindow.port.portRect.left;
  486.     }
  487.  
  488.  
  489. /* Get the global coordinate location of the window */
  490. OrdType                            GetWindowXStart(WinType* Window)
  491.     {
  492.         Point                            Delta = {0,0};
  493.  
  494.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  495.         CheckPtrExistence(Window);
  496.         /* this is really goofy, but I can't think of any other way of doing it. */
  497.         SetPort((WindowPtr)&(Window->ActualWindow));
  498.         LocalToGlobal(&Delta); /* find top-left with respect to screen */
  499.         return Delta.h;
  500.     }
  501.  
  502.  
  503. /* Get the global coordinate location of the window */
  504. OrdType                            GetWindowYStart(WinType* Window)
  505.     {
  506.         Point            Delta = {0,0};
  507.  
  508.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  509.         CheckPtrExistence(Window);
  510.         SetPort((WindowPtr)&(Window->ActualWindow));
  511.         LocalToGlobal(&Delta); /* find top-left with respect to screen */
  512.         return Delta.v - GetMBarHeight();
  513.     }
  514.  
  515.  
  516. /* Adjust the global position of the window. */
  517. void                                SetWindowPosition(WinType* Window, OrdType NewXLocation,
  518.                                             OrdType NewYLocation)
  519.     {
  520.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  521.         CheckPtrExistence(Window);
  522.         MoveWindow((WindowPtr)&(Window->ActualWindow),NewXLocation,
  523.             NewYLocation + GetMBarHeight(),False);
  524.     }
  525.  
  526.  
  527. /* Get what type of window it is */
  528. WinForm                            GetWindowKind(WinType* Window)
  529.     {
  530.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  531.         CheckPtrExistence(Window);
  532.         return Window->WhatKindOfWindow;
  533.     }
  534.  
  535.  
  536. /* allow system to resize window after user clicked in some area */
  537. void                                UserGrowWindow(WinType* Window, OrdType X, OrdType Y)
  538.     {
  539.         Rect                            Limits = {64,64,32767,32767};
  540.         Point                            Where;
  541.         unsigned long            NewSize;
  542.  
  543.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  544.         CheckPtrExistence(Window);
  545.         SetPort((WindowPtr)&(Window->ActualWindow));
  546.         Where.h = X;
  547.         Where.v = Y;
  548.         LocalToGlobal(&Where);
  549.         NewSize = GrowWindow((WindowPtr)&(Window->ActualWindow),Where,&Limits);
  550.         SizeWindow((WindowPtr)&(Window->ActualWindow),
  551.             NewSize & 0xffff,(NewSize >> 16) & 0xffff,False);
  552.         Limits.left = 0;
  553.         Limits.top = 0;
  554.         Limits.right = GetWindowWidth(Window);
  555.         Limits.bottom = GetWindowHeight(Window);
  556.         /* invalidate window so it gets redrawn */
  557.         EraseRect(&Limits);
  558.         InvalRect(&Limits);
  559.     }
  560.  
  561.  
  562. /* bring window to the top of the window stack.  this will be silently ignored */
  563. /* if there are dialog boxes open. */
  564. void                                ActivateThisWindow(WinType* Window)
  565.     {
  566.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  567.         CheckPtrExistence(Window);
  568.         if (ArrayGetLength(DialogBoxList) == 0)
  569.             {
  570.                 /* only do it if there aren't any dialog boxes */
  571.                 SelectWindow((WindowPtr)&(Window->ActualWindow));
  572.             }
  573.     }
  574.  
  575.  
  576. /* this function is used by MakeWindowFitOnScreen */
  577. static MyBoolean        SeeIfWindowFitsOnScreen(OrdType X, OrdType Y,
  578.                                             OrdType Width, OrdType Height)
  579.     {
  580.         RgnHandle                    OurRegion;
  581.         RgnHandle                    Intersection;
  582.         MyBoolean                    Result;
  583.  
  584.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  585.  
  586.         /* default value:  in case we run out of memory, don't do anything */
  587.         Result = True;
  588.         /* we add some constants in here to account for window title bar */
  589.         Y = Y + GetMBarHeight() - 19;
  590.         Height = Height + 19;
  591.  
  592.         /* create a region for the window the user wants to create */
  593.         OurRegion = NewRgn();
  594.         if (OurRegion != NIL)
  595.             {
  596.                 SetRectRgn(OurRegion,X,Y,X + Width,Y + Height);
  597.  
  598.                 /* create a region to get the intersection of the window & the screen */
  599.                 Intersection = NewRgn();
  600.                 if (Intersection != NIL)
  601.                     {
  602.                         /* find the intersection of the regions */
  603.                         SectRgn(GetGrayRgn(),OurRegion,Intersection);
  604.  
  605.                         /* if the window region and the intersection are equal, then the window */
  606.                         /* fits on the screen */
  607.                         Result = EqualRgn(Intersection,OurRegion);
  608.  
  609.                         DisposeRgn(Intersection);
  610.                     }
  611.  
  612.                 DisposeRgn(OurRegion);
  613.             }
  614.  
  615.         return Result;
  616.     }
  617.  
  618.  
  619. /* this routine helps make sure the rectangle fits on the screen.  If the rectangle */
  620. /* already fits on the screen, X and Y will not be adjusted, but if it doesn't, some */
  621. /* undefined adjustment will be made to ensure that the rectangle fits on the screen. */
  622. /* If the rectangle is so large that it can't be made to fit on the screen, then */
  623. /* the size of the window is reduced so that the window will fit on screen. */
  624. void                                MakeWindowFitOnScreen(OrdType* X, OrdType* Y,
  625.                                             OrdType* Width, OrdType* Height)
  626.     {
  627.         RgnHandle                    OurRegion;
  628.         RgnHandle                    Intersection;
  629.  
  630.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  631.         ERROR((X == NIL) || (Y == NIL) || (Width == NIL) || (Height == NIL),PRERR(ForceAbort,
  632.             "MakeWindowFitOnScreen:  an output parameter is NIL"));
  633.         if (!SeeIfWindowFitsOnScreen(*X,*Y,*Width,*Height))
  634.             {
  635.                 *X = 3;
  636.                 *Y = 23;
  637.                 if (!SeeIfWindowFitsOnScreen(*X,*Y,*Width,*Height))
  638.                     {
  639.                         if (*Width > GetScreenWidth() - *X - 2 - 1)
  640.                             {
  641.                                 *Width = GetScreenWidth() - *X - 2 - 1;
  642.                             }
  643.                         if (*Height > GetScreenHeight() - *Y - 2 - 1)
  644.                             {
  645.                                 *Height = GetScreenHeight() - *Y - 2 - 1;
  646.                             }
  647.                     }
  648.             }
  649.     }
  650.  
  651.  
  652. /* obtain the edge of a window, conforming to the user interface */
  653. /* guidelines of the implementation's platform */
  654. OrdType                            AlertLeftEdge(OrdType AlertWidth)
  655.     {
  656.         short                            Temp;
  657.  
  658.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  659.         Temp = (GetScreenWidth() - AlertWidth) / 2;
  660.         if (Temp < 4)
  661.             {
  662.                 Temp = 4;
  663.             }
  664.         return Temp;
  665.     }
  666.  
  667.  
  668. /* obtain the edge of a window, conforming to the user interface */
  669. /* guidelines of the implementation's platform */
  670. OrdType                            AlertTopEdge(OrdType AlertHeight)
  671.     {
  672.         short                            Temp;
  673.  
  674.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  675.         Temp = (GetScreenHeight() / 3) - AlertHeight;
  676.         if (Temp < 4 + 20 + GetMBarHeight())
  677.             {
  678.                 Temp = 4 + 20 + GetMBarHeight();
  679.             }
  680.         return Temp;
  681.     }
  682.  
  683.  
  684. /* obtain the edge of a window, conforming to the user interface */
  685. /* guidelines of the implementation's platform */
  686. OrdType                            DialogLeftEdge(OrdType DialogWidth)
  687.     {
  688.         short                            Temp;
  689.  
  690.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  691.         Temp = (GetScreenWidth() - DialogWidth) / 2;
  692.         if (Temp < 4)
  693.             {
  694.                 Temp = 4;
  695.             }
  696.         return Temp;
  697.     }
  698.  
  699.  
  700. /* obtain the edge of a window, conforming to the user interface */
  701. /* guidelines of the implementation's platform */
  702. OrdType                            DialogTopEdge(OrdType DialogHeight)
  703.     {
  704.         short                Temp;
  705.  
  706.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  707.         Temp = (GetScreenHeight() - DialogHeight) / 3;
  708.         if (Temp < 4 + 20 + GetMBarHeight())
  709.             {
  710.                 Temp = 4 + 20 + GetMBarHeight();
  711.             }
  712.         return Temp;
  713.     }
  714.  
  715.  
  716. /* change window's name.  name should be a null-terminated string.  the only windows */
  717. /* guarranteed to have a title bar are eDocumentWindow's. */
  718. void                                SetWindowName(WinType* Window, char* Name)
  719.     {
  720.         unsigned char            NameTemp[256];
  721.         long                            Scan;
  722.  
  723.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  724.         CheckPtrExistence(Window);
  725.         ERROR(Name == NIL,PRERR(ForceAbort,"SetWindowName:  name is NIL"));
  726.         Scan = 0;
  727.         while ((Scan < 255) && (Name[Scan] != 0))
  728.             {
  729.                 NameTemp[Scan + 1] = Name[Scan];
  730.                 Scan += 1;
  731.             }
  732.         NameTemp[0] = Scan;
  733.         SetWTitle((WindowPtr)&(Window->ActualWindow),NameTemp);
  734.     }
  735.  
  736.  
  737. /* invoke a window's update routine */
  738. void                                CallWindowUpdate(WinType* Window)
  739.     {
  740.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  741.         CheckPtrExistence(Window);
  742.         (*Window->UpdateRoutine)(Window->Refcon);
  743.     }
  744.  
  745.  
  746. /* if the program is doing something so that processing an update event would */
  747. /* cause it to crash, then the window is marked and will be redrawn as soon as */
  748. /* possible.   This is used during RelinquishCPU in the EventLoop module since */
  749. /* the windowing system might be in an inconsistent state when that routine is */
  750. /* called.  (If we ignored the event, then the window would not be redrawn at all) */
  751. void                                MarkForDeferredUpdate(WinType* Window)
  752.     {
  753.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  754.         CheckPtrExistence(Window);
  755.         if (ArrayFindElement(PendingDeferredUpdates,Window) < 0)
  756.             {
  757.                 /* don't add it to list unless it isn't there */
  758.                 /* if this fails, then it'll just not redraw the window. */
  759.                 ArrayAppendElement(PendingDeferredUpdates,Window);
  760.             }
  761.     }
  762.  
  763.  
  764. /* redraw all windows whose updates have been deferred */
  765. void                                PerformDeferredUpdates(void)
  766.     {
  767.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  768.         while (ArrayGetLength(PendingDeferredUpdates) != 0)
  769.             {
  770.                 WinType*                    Window;
  771.  
  772.                 /* get the window */
  773.                 Window = (WinType*)ArrayGetElement(PendingDeferredUpdates,0);
  774.                 CheckPtrExistence(Window);
  775.                 /* remove the window from the deferred update list */
  776.                 ArrayDeleteElement(PendingDeferredUpdates,0);
  777.                 /* erase window */
  778.                 SetClipRect(Window,0,0,GetWindowWidth(Window),GetWindowHeight(Window));
  779.                 DrawBoxErase(Window,0,0,GetWindowWidth(Window),GetWindowHeight(Window));
  780.                 /* call the redraw callback */
  781.                 CallWindowUpdate(Window);
  782.             }
  783.     }
  784.  
  785.  
  786. /* get the refcon from the window */
  787. void*                                GetWindowRefcon(WinType* Window)
  788.     {
  789.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  790.         CheckPtrExistence(Window);
  791.         return Window->Refcon;
  792.     }
  793.  
  794.  
  795. /* set the clipping rectangle for the window.  Drawing outside of this rectangle */
  796. /* will not be change any of the window */
  797. void                                SetClipRect(WinType* Window, OrdType Left, OrdType Top,
  798.                                             OrdType Width, OrdType Height)
  799.     {
  800.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  801.         CheckPtrExistence(Window);
  802.         SetPort((WindowPtr)&(Window->ActualWindow));
  803.         Window->CurrentClipRect.left = Left;
  804.         Window->CurrentClipRect.top = Top;
  805.         Window->CurrentClipRect.right = Left + Width;
  806.         Window->CurrentClipRect.bottom = Top + Height;
  807.         ClipRect(&(Window->CurrentClipRect));
  808.     }
  809.  
  810.  
  811. /* constrain the clipping rectangle for the window.  The new clipping rectangle is */
  812. /* the intersection of the specified one and the previous one. */
  813. void                                AddClipRect(WinType* Window, OrdType Left, OrdType Top,
  814.                                             OrdType Width, OrdType Height)
  815.     {
  816.         Rect                            Old;
  817.  
  818.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  819.         CheckPtrExistence(Window);
  820.         SetPort((WindowPtr)&(Window->ActualWindow));
  821.         Old = Window->CurrentClipRect;
  822.         Window->CurrentClipRect.left = Left;
  823.         Window->CurrentClipRect.top = Top;
  824.         Window->CurrentClipRect.right = Left + Width;
  825.         Window->CurrentClipRect.bottom = Top + Height;
  826.         SectRect(&(Window->CurrentClipRect),&Old,&(Window->CurrentClipRect));
  827.         ClipRect(&(Window->CurrentClipRect));
  828.     }
  829.  
  830.  
  831. /* returns True if any part of the specified rectangle in the window is visible. */
  832. /* this is used for making redrawing more efficient. */
  833. MyBoolean                        IsRectVisible(WinType* Window, OrdType Left, OrdType Top,
  834.                                             OrdType Width, OrdType Height)
  835.     {
  836.         Rect                            Location;
  837.  
  838.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  839.         CheckPtrExistence(Window);
  840.         Location.left = Left;
  841.         Location.top = Top;
  842.         Location.right = Left + Width;
  843.         Location.bottom = Top + Height;
  844.         return (MyBoolean)RectInRgn(&Location,Window->ActualWindow.port.visRgn);
  845.     }
  846.  
  847.  
  848. /* Draw a line one pixel thick.  XDisp and YDisp may be negative. */
  849. void                                DrawLine(WinType* Window, Patterns Pattern,
  850.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  851.     {
  852.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  853.         CheckPtrExistence(Window);
  854.         SetPort((WindowPtr)&(Window->ActualWindow));
  855.         PenPat(PatternMapping[Pattern - eWhite]);
  856.         PenMode(srcCopy);
  857.         MoveTo(X,Y);
  858.         LineTo(X + XDisp,Y + YDisp);
  859.     }
  860.  
  861.  
  862. /* Draw a box with a 1 pixel thick frame.  Note that the last pixel touched */
  863. /* is X + XDisp - 1 and Y + YDisp - 1. */
  864. void                                DrawBoxFrame(WinType* Window, Patterns Pattern,
  865.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  866.     {
  867.         Rect                            Temp;
  868.  
  869.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  870.         CheckPtrExistence(Window);
  871.         SetPort((WindowPtr)&(Window->ActualWindow));
  872.         PenPat(PatternMapping[Pattern - eWhite]);
  873.         PenMode(srcCopy);
  874.         Temp.left = X;
  875.         Temp.top = Y;
  876.         Temp.right = X + XDisp;
  877.         Temp.bottom = Y + YDisp;
  878.         FrameRect(&Temp);
  879.     }
  880.  
  881.  
  882. /* paint the box with the specified pattern */
  883. void                                DrawBoxPaint(WinType* Window, Patterns Pattern,
  884.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  885.     {
  886.         Rect                            Temp;
  887.  
  888.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  889.         CheckPtrExistence(Window);
  890.         SetPort((WindowPtr)&(Window->ActualWindow));
  891.         PenPat(PatternMapping[Pattern - eWhite]);
  892.         PenMode(srcCopy);
  893.         Temp.left = X;
  894.         Temp.top = Y;
  895.         Temp.right = X + XDisp;
  896.         Temp.bottom = Y + YDisp;
  897.         PaintRect(&Temp);
  898.     }
  899.  
  900.  
  901. /* paint the box with white */
  902. void                                DrawBoxErase(WinType* Window, OrdType X, OrdType Y,
  903.                                             OrdType XDisp, OrdType YDisp)
  904.     {
  905.         Rect                            Temp;
  906.  
  907.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  908.         CheckPtrExistence(Window);
  909.         SetPort((WindowPtr)&(Window->ActualWindow));
  910.         Temp.left = X;
  911.         Temp.top = Y;
  912.         Temp.right = X + XDisp;
  913.         Temp.bottom = Y + YDisp;
  914.         EraseRect(&Temp);
  915.     }
  916.  
  917.  
  918. #if 0
  919. /* And-mask the contents of the box with the pattern */
  920. void                                DrawBoxScreen(WinType* Window, Patterns Pattern,
  921.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp);
  922.     {
  923.         Rect                            Temp;
  924.  
  925.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  926.         CheckPtrExistence(Window);
  927.         SetPort((WindowPtr)&(Window->ActualWindow));
  928.         PenPat(PatternMapping[Pattern - eWhite]);
  929.         PenMode(srcBic);
  930.         Temp.left = X;
  931.         Temp.top = Y;
  932.         Temp.right = X + XDisp;
  933.         Temp.bottom = Y + YDisp;
  934.         PaintRect(&Temp);
  935.     }
  936. #endif
  937.  
  938.  
  939. /* Draw a box, but round off the corners with circles. */
  940. void                                DrawRoundBoxFrame(WinType* Window, Patterns Pattern,
  941.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp,
  942.                                             OrdType DiameterX, OrdType DiameterY)
  943.     {
  944.         Rect                            Temp;
  945.  
  946.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  947.         CheckPtrExistence(Window);
  948.         SetPort((WindowPtr)&(Window->ActualWindow));
  949.         PenPat(PatternMapping[Pattern - eWhite]);
  950.         PenMode(srcCopy);
  951.         Temp.left = X;
  952.         Temp.top = Y;
  953.         Temp.right = X + XDisp;
  954.         Temp.bottom = Y + YDisp;
  955.         FrameRoundRect(&Temp,DiameterX,DiameterY);
  956.     }
  957.  
  958.  
  959. /* Draw a box, but round off the corners with circles. */
  960. void                                DrawRoundBoxPaint(WinType* Window, Patterns Pattern,
  961.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp,
  962.                                             OrdType DiameterX, OrdType DiameterY)
  963.     {
  964.         Rect                            Temp;
  965.  
  966.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  967.         CheckPtrExistence(Window);
  968.         SetPort((WindowPtr)&(Window->ActualWindow));
  969.         PenPat(PatternMapping[Pattern - eWhite]);
  970.         PenMode(srcCopy);
  971.         Temp.left = X;
  972.         Temp.top = Y;
  973.         Temp.right = X + XDisp;
  974.         Temp.bottom = Y + YDisp;
  975.         PaintRoundRect(&Temp,DiameterX,DiameterY);
  976.     }
  977.  
  978.  
  979. /* Draw a box, but round off the corners with circles. */
  980. void                                DrawRoundBoxErase(WinType* Window, OrdType X, OrdType Y,
  981.                                             OrdType XDisp, OrdType YDisp, OrdType DiameterX, OrdType DiameterY)
  982.     {
  983.         Rect                            Temp;
  984.  
  985.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  986.         CheckPtrExistence(Window);
  987.         SetPort((WindowPtr)&(Window->ActualWindow));
  988.         Temp.left = X;
  989.         Temp.top = Y;
  990.         Temp.right = X + XDisp;
  991.         Temp.bottom = Y + YDisp;
  992.         EraseRoundRect(&Temp,DiameterX,DiameterY);
  993.     }
  994.  
  995.  
  996. void                                DrawCircleFrame(WinType* Window, Patterns Pattern,
  997.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  998.     {
  999.         Rect                            Temp;
  1000.  
  1001.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1002.         CheckPtrExistence(Window);
  1003.         SetPort((WindowPtr)&(Window->ActualWindow));
  1004.         PenPat(PatternMapping[Pattern - eWhite]);
  1005.         PenMode(srcCopy);
  1006.         Temp.left = X;
  1007.         Temp.top = Y;
  1008.         Temp.right = X + XDisp;
  1009.         Temp.bottom = Y + YDisp;
  1010.         FrameOval(&Temp);
  1011.     }
  1012.  
  1013.  
  1014. void                                DrawCirclePaint(WinType* Window, Patterns Pattern,
  1015.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  1016.     {
  1017.         Rect                            Temp;
  1018.  
  1019.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1020.         CheckPtrExistence(Window);
  1021.         SetPort((WindowPtr)&(Window->ActualWindow));
  1022.         PenPat(PatternMapping[Pattern - eWhite]);
  1023.         PenMode(srcCopy);
  1024.         Temp.left = X;
  1025.         Temp.top = Y;
  1026.         Temp.right = X + XDisp;
  1027.         Temp.bottom = Y + YDisp;
  1028.         PaintOval(&Temp);
  1029.     }
  1030.  
  1031.  
  1032. void                                DrawCircleErase(WinType* Window, OrdType X, OrdType Y,
  1033.                                             OrdType XDisp, OrdType YDisp)
  1034.     {
  1035.         Rect            Temp;
  1036.  
  1037.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1038.         CheckPtrExistence(Window);
  1039.         SetPort((WindowPtr)&(Window->ActualWindow));
  1040.         Temp.left = X;
  1041.         Temp.top = Y;
  1042.         Temp.right = X + XDisp;
  1043.         Temp.bottom = Y + YDisp;
  1044.         EraseOval(&Temp);
  1045.     }
  1046.  
  1047.  
  1048. /* fill a triangle */
  1049. void                                DrawTrianglePaint(WinType* Window, Patterns Pattern, OrdType X1,
  1050.                                             OrdType Y1, OrdType X2, OrdType Y2, OrdType X3, OrdType Y3)
  1051.     {
  1052.         PolyHandle                Poly;
  1053.  
  1054.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1055.         CheckPtrExistence(Window);
  1056.         SetPort((WindowPtr)&(Window->ActualWindow));
  1057.         Poly = OpenPoly();
  1058.         MoveTo(X1,Y1);
  1059.         LineTo(X2,Y2);
  1060.         LineTo(X3,Y3);
  1061.         LineTo(X1,Y1);
  1062.         ClosePoly();
  1063.         PenPat(PatternMapping[Pattern - eWhite]);
  1064.         PenMode(srcCopy);
  1065.         PaintPoly(Poly);
  1066.         KillPoly(Poly);
  1067.     }
  1068.  
  1069.  
  1070. /* Get the ID of a heavier screen font (Macintosh == Chicago) */
  1071. FontType                        GetUglyFont(void)
  1072.     {
  1073.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1074.         return systemFont;
  1075.     }
  1076.  
  1077.  
  1078. /* Get the ID of the default screen font (Macintosh == Geneva) */
  1079. FontType                        GetScreenFont(void)
  1080.     {
  1081.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1082.         return geneva;
  1083.     }
  1084.  
  1085.  
  1086. /* Get the ID of the normal monospaced font, usually courier or monaco */
  1087. FontType                        GetMonospacedFont(void)
  1088.     {
  1089.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1090.         return monaco;
  1091.     }
  1092.  
  1093.  
  1094. /* Get the ID of the named font.  If no such font exists, then it is an error */
  1095. FontType                        GetFontByName(char* Name)
  1096.     {
  1097.         unsigned char            NameTemp[256];
  1098.         long                            Scan;
  1099.         short                            FontID;
  1100.  
  1101.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1102.         Scan = 0;
  1103.         while ((Scan < 255) && (Name[Scan] != 0))
  1104.             {
  1105.                 NameTemp[Scan + 1] = Name[Scan];
  1106.                 Scan += 1;
  1107.             }
  1108.         NameTemp[0] = Scan;
  1109.         GetFNum(NameTemp,&FontID);
  1110. #if DEBUG
  1111.         if (FontID == 0)
  1112.             {
  1113.                 unsigned char            SysFontName[256];
  1114.  
  1115.                 GetFontName(0,SysFontName);
  1116.                 if (!EqualString(NameTemp,SysFontName,False,False))
  1117.                     {
  1118.                         PRERR(AllowResume,"GetFontByName:  font doesn't exist");
  1119.                     }
  1120.             }
  1121. #endif
  1122.         return FontID;
  1123.     }
  1124.  
  1125.  
  1126. /* Get the total number of pixels high a line is using the specified font */
  1127. OrdType                            GetFontHeight(FontType FontID, FontSizeType PointSize)
  1128.     {
  1129.         GrafPort                    Temp;
  1130.         FontInfo                    TheFont;
  1131.  
  1132.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1133.         OpenPort(&Temp);
  1134.         TextFont(FontID);
  1135.         TextFace(0);
  1136.         TextMode(srcCopy);
  1137.         TextSize(PointSize);
  1138.         SpaceExtra(0);
  1139.         GetFontInfo(&TheFont);
  1140.         ClosePort(&Temp);
  1141.         return TheFont.ascent + TheFont.descent + TheFont.leading;
  1142.     }
  1143.  
  1144.  
  1145. /* return a Ptr containing the name of the font, null terminated */
  1146. char*                                GetNameOfFont(FontType FontID)
  1147.     {
  1148.         unsigned char            DaFontName[256];
  1149.         char*                            Temp;
  1150.  
  1151.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1152.         GetFontName(FontID,DaFontName);
  1153.         ERROR(DaFontName[0] == 0,PRERR(AllowResume,"GetNameOfFont:  nonexistent font"));
  1154.         Temp = AllocPtrCanFail(DaFontName[0] + 1,"FontName");
  1155.         if (Temp != NIL)
  1156.             {
  1157.                 CopyData((char*)&(DaFontName[1]),&(Temp[0]),DaFontName[0]);
  1158.                 Temp[DaFontName[0]] = 0;
  1159.             }
  1160.         return Temp;
  1161.     }
  1162.  
  1163.  
  1164. /* get number of fonts */
  1165. long                                GetNumAvailableFonts(void)
  1166.     {
  1167.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1168.         return CountMItems(FunnyFontMenu);
  1169.     }
  1170.  
  1171.  
  1172. /* get the FontType of an indexed font. indices are from 0 to GetNumAvailableFonts - 1 */
  1173. FontType                        GetIndexedFont(long FontIndex)
  1174.     {
  1175.         short                            DaID;
  1176.         unsigned char            DaName[256];
  1177.  
  1178.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1179.         ERROR((FontIndex < 0) || (FontIndex >= GetNumAvailableFonts()),PRERR(ForceAbort,
  1180.             "GetIndexedFont:  index out of range"));
  1181.         /* we cleverly make a menu, pile the fonts in there, and then extract */
  1182.         GetItem(FunnyFontMenu,FontIndex + 1,DaName);
  1183.         GetFNum(DaName,&DaID);
  1184.         return DaID;
  1185.     }
  1186.  
  1187.  
  1188. /* find the total number of pixels long the string of text is */
  1189. OrdType                            LengthOfText(FontType Font, FontSizeType PointSize, char* Text,
  1190.                                             long Length, FontStyleType FontStyle)
  1191.     {
  1192.         GrafPort                    Temp;
  1193.         long                            CurrentLinePixels;
  1194.         Style                            FontThangs;
  1195.  
  1196.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1197.         /* open a temporary port to work from */
  1198.         OpenPort(&Temp);
  1199.         /* set font */
  1200.         TextFont(Font);
  1201.         /* figure out what style to use */
  1202.         FontThangs = 0;
  1203.         if ((FontStyle & eBold) != 0)
  1204.             {
  1205.                 FontThangs |= bold;
  1206.             }
  1207.         if ((FontStyle & eItalic) != 0)
  1208.             {
  1209.                 FontThangs |= italic;
  1210.             }
  1211.         if ((FontStyle & eUnderline) != 0)
  1212.             {
  1213.                 FontThangs |= underline;
  1214.             }
  1215.         TextFace(FontThangs);
  1216.         TextMode(srcCopy);
  1217.         TextSize(PointSize);
  1218.         SpaceExtra(0);
  1219.         /* loop through string & add up lengths */
  1220.         CurrentLinePixels = 0;
  1221.         while (Length > 0)
  1222.             {
  1223.                 if (Length > MAXTEXTSIZING)
  1224.                     {
  1225.                         CurrentLinePixels += TextWidth(Text,0,MAXTEXTSIZING);
  1226.                         Length -= MAXTEXTSIZING;
  1227.                         Text += MAXTEXTSIZING;
  1228.                     }
  1229.                  else
  1230.                     {
  1231.                         CurrentLinePixels += TextWidth(Text,0,Length);
  1232.                         Length = 0;
  1233.                     }
  1234.             }
  1235.         ClosePort(&Temp);
  1236.         return CurrentLinePixels;
  1237.     }
  1238.  
  1239.  
  1240. /* draw a line of text */
  1241. void                                DrawTextLine(WinType* Window, FontType Font, FontSizeType PointSize,
  1242.                                             char* Text, long Length, OrdType X, OrdType Y,
  1243.                                             FontStyleType FontStyle)
  1244.     {
  1245.         FontInfo                    Info;
  1246.         Style                            FontThangs;
  1247.  
  1248.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1249.         ERROR(Text == NIL,PRERR(ForceAbort,"DrawTextLine:  Text is NIL"));
  1250.         CheckPtrExistence(Window);
  1251.         SetPort((WindowPtr)&(Window->ActualWindow));
  1252.         TextFont(Font);
  1253.         FontThangs = 0;
  1254.         if ((FontStyle & eBold) != 0)
  1255.             {
  1256.                 FontThangs |= bold;
  1257.             }
  1258.         if ((FontStyle & eItalic) != 0)
  1259.             {
  1260.                 FontThangs |= italic;
  1261.             }
  1262.         if ((FontStyle & eUnderline) != 0)
  1263.             {
  1264.                 FontThangs |= underline;
  1265.             }
  1266.         TextFace(FontThangs);
  1267.         TextMode(srcCopy);
  1268.         TextSize(PointSize);
  1269.         SpaceExtra(0);
  1270.         GetFontInfo(&Info);
  1271.         MoveTo(X,Y + Info.leading + Info.ascent);
  1272.         while (Length > 0)
  1273.             {
  1274.                 if (Length > MAXTEXTSIZING)
  1275.                     {
  1276.                         DrawText(Text,0,MAXTEXTSIZING);
  1277.                         Length -= MAXTEXTSIZING;
  1278.                         Text += MAXTEXTSIZING;
  1279.                     }
  1280.                  else
  1281.                     {
  1282.                         DrawText(Text,0,Length);
  1283.                         Length = 0;
  1284.                     }
  1285.             }
  1286.         if (Info.leading > 0)
  1287.             {
  1288.                 Rect                EraseMe;
  1289.  
  1290.                 /* since srcCopy doesn't erase the leading, we have to do it. */
  1291.                 EraseMe.left = X;
  1292.                 EraseMe.top = Y;
  1293.                 EraseMe.right = Window->ActualWindow.port.pnLoc.h;
  1294.                 EraseMe.bottom = EraseMe.top + Info.leading;
  1295.                 EraseRect(&EraseMe);
  1296.             }
  1297.     }
  1298.  
  1299.  
  1300. /* draw a line of text, but with white background and black letters */
  1301. void                                InvertedTextLine(WinType* Window, FontType Font,
  1302.                                             FontSizeType PointSize, char* Text, long Length,
  1303.                                             OrdType X, OrdType Y, FontStyleType FontStyle)
  1304.     {
  1305.         FontInfo                    Info;
  1306.         Style                            FontThangs;
  1307.  
  1308.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1309.         CheckPtrExistence(Window);
  1310.         SetPort((WindowPtr)&(Window->ActualWindow));
  1311.         TextFont(Font);
  1312.         FontThangs = 0;
  1313.         if ((FontStyle & eBold) != 0)
  1314.             {
  1315.                 FontThangs |= bold;
  1316.             }
  1317.         if ((FontStyle & eItalic) != 0)
  1318.             {
  1319.                 FontThangs |= italic;
  1320.             }
  1321.         if ((FontStyle & eUnderline) != 0)
  1322.             {
  1323.                 FontThangs |= underline;
  1324.             }
  1325.         TextFace(FontThangs);
  1326.         TextMode(notSrcCopy);
  1327.         TextSize(PointSize);
  1328.         SpaceExtra(0);
  1329.         GetFontInfo(&Info);
  1330.         MoveTo(X,Y + Info.leading + Info.ascent);
  1331.         while (Length > 0)
  1332.             {
  1333.                 if (Length > MAXTEXTSIZING)
  1334.                     {
  1335.                         DrawText(Text,0,MAXTEXTSIZING);
  1336.                         Length -= MAXTEXTSIZING;
  1337.                         Text += MAXTEXTSIZING;
  1338.                     }
  1339.                  else
  1340.                     {
  1341.                         DrawText(Text,0,Length);
  1342.                         Length = 0;
  1343.                     }
  1344.             }
  1345.         if (Info.leading > 0)
  1346.             {
  1347.                 Rect                EraseMe;
  1348.  
  1349.                 /* since srcCopy doesn't erase the leading, we have to do it. */
  1350.                 EraseMe.left = X;
  1351.                 EraseMe.top = Y;
  1352.                 EraseMe.right = Window->ActualWindow.port.pnLoc.h;
  1353.                 EraseMe.bottom = EraseMe.top + Info.leading;
  1354.                 PenPat(qd.black);
  1355.                 PenMode(patCopy);
  1356.                 PaintRect(&EraseMe);
  1357.             }
  1358.     }
  1359.  
  1360.  
  1361. /* move the specified rectangle of of pixels. XDisplacement and YDisplacement */
  1362. /* positive mean to the right and down.  Area opened up is erased with white. */
  1363. /* no area outside of the rectangle is touched. */
  1364. void                                ScrollArea(WinType* Window, OrdType Left, OrdType Top, OrdType Width,
  1365.                                             OrdType Height, OrdType XDisplacement, OrdType YDisplacement)
  1366.     {
  1367.         Rect                            Where;
  1368.         RgnHandle                    UpdateRegion;
  1369.         RgnHandle                    ScreenRegion;
  1370.  
  1371.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1372.         CheckPtrExistence(Window);
  1373.         SetPort((WindowPtr)&(Window->ActualWindow));
  1374.         Where.left = Left;
  1375.         Where.top = Top;
  1376.         Where.right = Left + Width;
  1377.         Where.bottom = Top + Height;
  1378.         UpdateRegion = NewRgn();
  1379.         if (UpdateRegion != NIL)
  1380.             {
  1381.                 ScrollRect(&Where,XDisplacement,YDisplacement,UpdateRegion);
  1382.                 /* we discard the update region because the scroller is expected to redraw */
  1383.                 /* it himself without getting and update event */
  1384.                 DisposeRgn(UpdateRegion);
  1385.             }
  1386.     }
  1387.  
  1388.  
  1389. /* convert a raw packed-byte list of data (upper bit of each byte is leftmost */
  1390. /* on the screen) to an internal bitmap */
  1391. Bitmap*                            MakeBitmap(unsigned char* RawData, OrdType Width, OrdType Height,
  1392.                                             long BytesPerRow)
  1393.     {
  1394.         short                            TrueBytesPerRow;
  1395.         short                            RowScan;
  1396.         short                            ColumnScan;
  1397.         long                            MapIndex;
  1398.         Bitmap*                        Data;
  1399.  
  1400.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1401.         ERROR(RawData == NIL,PRERR(ForceAbort,"MakeBitmap:  data is NIL"));
  1402.         /* calculate local bytes per row so that it's a long-word multiple */
  1403.         TrueBytesPerRow = ((Width + (8 * sizeof(long)) - 1) / (8 * sizeof(long))) * 4;
  1404.         Data = (Bitmap*)AllocPtrCanFail(TrueBytesPerRow * Height + sizeof(Bitmap),"Bitmap");
  1405.         if (Data == NIL)
  1406.             {
  1407.                 return NIL;
  1408.             }
  1409.         MapIndex = 0;
  1410.         for (RowScan = 0; RowScan < Height; RowScan += 1)
  1411.             {
  1412.                 /* copy over one row worth of data */
  1413.                 for (ColumnScan = 0; ColumnScan < BytesPerRow; ColumnScan += 1)
  1414.                     {
  1415.                         Data->Data[MapIndex + ColumnScan] = RawData[ColumnScan];
  1416.                     }
  1417.                 /* pad the extra space with zeros */
  1418.                 for (ColumnScan = 0; ColumnScan < TrueBytesPerRow - BytesPerRow;
  1419.                     ColumnScan += 1)
  1420.                     {
  1421.                         Data->Data[MapIndex + ColumnScan + BytesPerRow] = 0;
  1422.                     }
  1423.                 MapIndex += TrueBytesPerRow;
  1424.                 RawData += BytesPerRow;
  1425.             }
  1426.         /* assign internal values */
  1427.         Data->Width = Width;
  1428.         Data->Height = Height;
  1429.         Data->BytesPerRow = TrueBytesPerRow;
  1430.         /* initialize the system's bitmap */
  1431.         Data->SystemBitmap.baseAddr = (char*)(Data->Data);
  1432.         Data->SystemBitmap.rowBytes = TrueBytesPerRow;
  1433.         Data->SystemBitmap.bounds.left = 0;
  1434.         Data->SystemBitmap.bounds.top = 0;
  1435.         Data->SystemBitmap.bounds.right = Data->Width;
  1436.         Data->SystemBitmap.bounds.bottom = Data->Height;
  1437.         return Data;
  1438.     }
  1439.  
  1440.  
  1441. /* dispose of the bitmap made by MakeBitmap */
  1442. void                                DisposeBitmap(Bitmap* TheBitmap)
  1443.     {
  1444.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1445.         ReleasePtr((char*)TheBitmap);
  1446.     }
  1447.  
  1448.  
  1449. /* copy the bitmap to the area specified. */
  1450. void                                DrawBitmap(WinType* Window, OrdType X, OrdType Y, Bitmap* TheBitmap)
  1451.     {
  1452.         Rect                            DestRect;
  1453.  
  1454.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1455.         CheckPtrExistence(Window);
  1456.         CheckPtrExistence(TheBitmap);
  1457.         SetPort((WindowPtr)&(Window->ActualWindow));
  1458.         DestRect.left = X;
  1459.         DestRect.top = Y;
  1460.         DestRect.right = X + TheBitmap->Width;
  1461.         DestRect.bottom = Y + TheBitmap->Height;
  1462.         CopyBits(&(TheBitmap->SystemBitmap),&(Window->ActualWindow.port.portBits),
  1463.             &(TheBitmap->SystemBitmap.bounds),&DestRect,srcCopy,NIL);
  1464.     }
  1465.  
  1466.  
  1467. /* logical-or the bitmap onto the window */
  1468. void                                OrBitmap(WinType* Window, OrdType X, OrdType Y, Bitmap* TheBitmap)
  1469.     {
  1470.         Rect                            DestRect;
  1471.  
  1472.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1473.         CheckPtrExistence(Window);
  1474.         CheckPtrExistence(TheBitmap);
  1475.         SetPort((WindowPtr)&(Window->ActualWindow));
  1476.         DestRect.left = X;
  1477.         DestRect.top = Y;
  1478.         DestRect.right = X + TheBitmap->Width;
  1479.         DestRect.bottom = Y + TheBitmap->Height;
  1480.         CopyBits(&(TheBitmap->SystemBitmap),&(Window->ActualWindow.port.portBits),
  1481.             &(TheBitmap->SystemBitmap.bounds),&DestRect,srcOr,NIL);
  1482.     }
  1483.  
  1484.  
  1485. /* Bit-clear the bitmap onto the window:  Where the bitmap is set, the */
  1486. /* window will be erased; otherwise the window will be untouched */
  1487. void                                BicBitmap(WinType* Window, OrdType X, OrdType Y, Bitmap* TheBitmap)
  1488.     {
  1489.         Rect                            DestRect;
  1490.  
  1491.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1492.         CheckPtrExistence(Window);
  1493.         CheckPtrExistence(TheBitmap);
  1494.         SetPort((WindowPtr)&(Window->ActualWindow));
  1495.         DestRect.left = X;
  1496.         DestRect.top = Y;
  1497.         DestRect.right = X + TheBitmap->Width;
  1498.         DestRect.bottom = Y + TheBitmap->Height;
  1499.         CopyBits(&(TheBitmap->SystemBitmap),&(Window->ActualWindow.port.portBits),
  1500.             &(TheBitmap->SystemBitmap.bounds),&DestRect,srcBic,NIL);
  1501.     }
  1502.  
  1503.  
  1504. /* duplicate the bitmap */
  1505. Bitmap*                            DuplicateBitmap(Bitmap* Original)
  1506.     {
  1507.         Bitmap*                        Copy;
  1508.         long                            TotalSize;
  1509.  
  1510.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1511.         CheckPtrExistence(Original);
  1512.         /* this is easy since there are no sub-objects */
  1513.         TotalSize = PtrSize((char*)Original);
  1514.         Copy = (Bitmap*)AllocPtrCanFail(TotalSize,"DuplicateBitmap");
  1515.         if (Copy != NIL)
  1516.             {
  1517.                 CopyData((char*)Original,(char*)Copy,TotalSize);
  1518.                 Copy->SystemBitmap.baseAddr = (char*)(Copy->Data);
  1519.             }
  1520.         return Copy;
  1521.     }
  1522.  
  1523.  
  1524. /* logical-or the first bitmap onto the second.  sizes must be the same */
  1525. void                                BitmapOrIntoBitmap(Bitmap* NotChanged, Bitmap* IsChanged)
  1526.     {
  1527.         long                            Scan;
  1528.         long                            Limit;
  1529.  
  1530.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1531.         CheckPtrExistence(NotChanged);
  1532.         CheckPtrExistence(IsChanged);
  1533.         ERROR((NotChanged->BytesPerRow != IsChanged->BytesPerRow)
  1534.             || (NotChanged->Width != IsChanged->Width)
  1535.             || (NotChanged->Height != IsChanged->Height),PRERR(ForceAbort,
  1536.             "BitmapOrIntoBitmap:  bitmaps are not the same size"));
  1537.         /* we can perform operations on long words since we ensure that our */
  1538.         /* internal bitmap representation is long-word aligned */
  1539.         Limit = (IsChanged->BytesPerRow * IsChanged->Height) / sizeof(unsigned long);
  1540.         for (Scan = 0; Scan < Limit; Scan += 1)
  1541.             {
  1542.                 PRNGCHK(IsChanged,&(((unsigned long*)(IsChanged->Data))[Scan]),
  1543.                     sizeof(unsigned long));
  1544.                 PRNGCHK(NotChanged,&(((unsigned long*)(NotChanged->Data))[Scan]),
  1545.                     sizeof(unsigned long));
  1546.                 ((unsigned long*)(IsChanged->Data))[Scan]
  1547.                     |= ((unsigned long*)(NotChanged->Data))[Scan];
  1548.             }
  1549.     }
  1550.  
  1551.  
  1552. /* logical-and the first bitmap onto the second.  sizes must be the same */
  1553. void                                BitmapAndIntoBitmap(Bitmap* NotChanged, Bitmap* IsChanged)
  1554.     {
  1555.         long                            Scan;
  1556.         long                            Limit;
  1557.  
  1558.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1559.         CheckPtrExistence(NotChanged);
  1560.         CheckPtrExistence(IsChanged);
  1561.         ERROR((NotChanged->BytesPerRow != IsChanged->BytesPerRow)
  1562.             || (NotChanged->Width != IsChanged->Width)
  1563.             || (NotChanged->Height != IsChanged->Height),PRERR(ForceAbort,
  1564.             "BitmapAndIntoBitmap:  bitmaps are not the same size"));
  1565.         /* we can perform operations on long words since we ensure that our */
  1566.         /* internal bitmap representation is long-word aligned */
  1567.         Limit = (IsChanged->BytesPerRow * IsChanged->Height) / sizeof(unsigned long);
  1568.         for (Scan = 0; Scan < Limit; Scan += 1)
  1569.             {
  1570.                 PRNGCHK(IsChanged,&(((unsigned long*)(IsChanged->Data))[Scan]),
  1571.                     sizeof(unsigned long));
  1572.                 PRNGCHK(NotChanged,&(((unsigned long*)(NotChanged->Data))[Scan]),
  1573.                     sizeof(unsigned long));
  1574.                 ((unsigned long*)(IsChanged->Data))[Scan]
  1575.                     &= ((unsigned long*)(NotChanged->Data))[Scan];
  1576.             }
  1577.     }
  1578.